package com.cskaoyan.javase._0abstract._0introduction;

/**
 * 以下猫狗继承案例，是一个非常基础的继承语法的代码。
 * 思考一下Animal类的继承体系，有什么问题吗？
 * 从以下两个角度分析：
 * 从代码角度上，有没有冗余代码？
 * 从设计角度上，在这个案例中，会存在一个动物对象吗？
 *
 * 分析一下
 * 单纯从代码角度上，有没有冗余代码？
 * 实际上是有的。从方法调用的角度考虑，Animal类当中的shout方法从来没有被调用过。该方法单纯就是让子类继承并重写的，它实际上没有被调用的需求。从最理想的角度上来说，它的方法体是可以去掉的，仅保留一个声明让子类去重写就可以了。
 * 当然代码多几行少几行并不重要，重要是：从设计角度出发，Animal类是一个抽象的概念，用于指代所有动物。程序中根本不需要创建它的对象。而且对于一个抽象的概念，也不应该、也不可能去描述它的行为。
 *
 * 综上，我们提出两个改进的方向：
 *      1.Animal类就是作为顶层抽象祖先类而存在的，不需要创建对象，于是干脆不要创建对象了。
 *      2.Animal类当中的shout方法不需要方法体，仅用于作为被继承和重写一个方法声明。
 *      显然,shout方法肯定不会是一个普通方法,Animal类也不会是一个普通类
 *
 * 直接去掉方法体,报错:
 * Missing method body, or declare abstract
 * 一个方法要么有方法体,要么声明为抽象
 *
 * 抽象方法的语法:
 * [修饰符列表] abstract 返回值类型 方法名(形参列表);
 *
 * 直接在普通类中声明抽象方法,会报错:
 *      1.Abstract method in non-abstract class
 *      2.Class 'Animal' must either be declared abstract or
 *          implement abstract method 'shout()' in 'Animal'
 * 抽象方法不能处在普通类中,必须在抽象类中.
 * 普通类必须实现抽象方法,不能有抽象方法
 *
 * 抽象类的声明语法:
 * [修饰符列表] abstract class 类名{
 *   // 类体
 * }
 * 以上在抽象类中定义了抽象方法,抽象类在整个体系中,仍然是父类
 * 仍然可以父类引用指向子类对象
 * 仍然存在多态现象
 * 并且Animal已成为抽象祖先类了,不能再创建它的对象了
 *
 * @since 17:04
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Animal a;
        a = new Cat();
        a.shout();
        a = new Dog();
        a.shout();

        // 'Animal' is abstract; cannot be instantiated
        // new Animal();
    }
}

// 抽象类
abstract class Animal {
    // 抽象方法
    public abstract void shout();
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫叫");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫");
    }
}